package com.cea.papyrus.diagram.classdiagram.commands;

import org.eclipse.emf.ecore.EClass;
import org.eclipse.gef.commands.Command;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.ClassifierTemplateParameter;
import org.eclipse.uml2.uml.Generalization;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.ParameterableElement;
import org.eclipse.uml2.uml.TemplateParameter;
import org.eclipse.uml2.uml.UMLFactory;

public class ElementOwnedByATemplateParameterCreateCommand extends Command{

	public final static int OWNED_PARAMETERED_ELEMENT = 0 ;
	public final static int OWNED_DEFAULT = 1 ;
	
	/**
	 * Created element.
	 */
	private ParameterableElement createdOwnedElement ;
	
	/**
	 * parent of the created element.
	 */
	private TemplateParameter umlParentTemplateParameter ;
	
	/**
	 * generalization created when an owned default is created,
	 * and the template parameter is a ClassifierTemplateParameter,
	 * and the classifier template parameter has a constraining classifier
	 */
	private Generalization createdGeneralization ;
	
	/**
	 * an int representing the property subset of TemplateParameter.ownedElements()
	 * must be equal to OWNED_PARAMETERED_ELEMENT or OWNED_DEFAULT
	 */
	private int ownedElementPropertyKind ;
	
	/**
	 * element metaclass.
	 */
	private EClass elementMetaClass ;
	
	private Class elementClass;
	
	public ElementOwnedByATemplateParameterCreateCommand(EClass elementMetaClass, Class elementClass, TemplateParameter umlParent, int ownedElementPropertyKind) {
		this.umlParentTemplateParameter = umlParent ;
		this.elementMetaClass = elementMetaClass ;
		this.ownedElementPropertyKind = ownedElementPropertyKind ;
		this.createdGeneralization = null ;
		this.elementClass=elementClass;
		switch (this.ownedElementPropertyKind) {
		case OWNED_PARAMETERED_ELEMENT:
			super.setLabel("Creation of an owned parametered " + elementMetaClass.getName()) ;
			break ;
		case OWNED_DEFAULT:
			super.setLabel("Creation of an owned default " + elementMetaClass.getName()) ;
			break ;
		default:
			break;
		}
	}
	
	public void execute() {
		switch (ownedElementPropertyKind) {
		case OWNED_PARAMETERED_ELEMENT:
			createdOwnedElement = umlParentTemplateParameter.createOwnedParameteredElement(elementMetaClass) ;
			((NamedElement)createdOwnedElement).setName("Param" + elementClass.getSimpleName()) ;
			createdOwnedElement.setTemplateParameter(umlParentTemplateParameter) ;
			createdOwnedElement.setOwningTemplateParameter(umlParentTemplateParameter) ;
			break;
		case OWNED_DEFAULT:
			createdOwnedElement = umlParentTemplateParameter.createOwnedDefault(elementMetaClass) ;
			((NamedElement)createdOwnedElement).setName("DefaultFor" + ((NamedElement)umlParentTemplateParameter.getParameteredElement()).getName()) ;
			if (umlParentTemplateParameter instanceof ClassifierTemplateParameter) {
				ClassifierTemplateParameter classifierTP = (ClassifierTemplateParameter)umlParentTemplateParameter ;
				classifierTP.setDefaultClassifier((Classifier)createdOwnedElement) ;
				if (classifierTP.getConstrainingClassifier() != null) {
					createdGeneralization = UMLFactory.eINSTANCE.createGeneralization() ;
					createdGeneralization.setGeneral(classifierTP.getConstrainingClassifier()) ;
					createdGeneralization.setSpecific(classifierTP.getDefaultClassifier()) ;
				}
			}
			break;
		default:
			break;
		}
	}
	
	public boolean canExecute() {
		return umlParentTemplateParameter instanceof TemplateParameter ; 
	}
	
	public void redo() {
		execute() ;
	}
	
	public void undo() {
		switch (this.ownedElementPropertyKind) {
		case OWNED_PARAMETERED_ELEMENT:
			umlParentTemplateParameter.setOwnedParameteredElement(null) ;
			umlParentTemplateParameter.setParameteredElement(null) ;
			createdOwnedElement.setOwningTemplateParameter(null) ;
			createdOwnedElement.setTemplateParameter(null) ;
			break;
		case OWNED_DEFAULT:
			umlParentTemplateParameter.setOwnedDefault(null) ;
			umlParentTemplateParameter.setDefault(null) ;
			if (umlParentTemplateParameter instanceof ClassifierTemplateParameter) {
				ClassifierTemplateParameter classifierTP = (ClassifierTemplateParameter)umlParentTemplateParameter ;
				classifierTP.setDefaultClassifier(null) ;
				if (createdGeneralization != null) {
					createdGeneralization.setGeneral(null) ;
					createdGeneralization.setSpecific(null) ;
				}
			}
			break;
		default:
			break;
		}
	}
	
	public boolean canUndo() {
		return createdOwnedElement != null ;
	}
	
	public boolean canRedo() {
		return createdOwnedElement != null ;
	}
}
